﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Phone.Shell;

namespace PhysicsSimulator
{
    public partial class SpringsPendulumPage : PhoneApplicationPage
    {
        ContentManager contentManager;
        GameTimer timer;
        SpriteBatch spriteBatch;

        UIElementRenderer elementRenderer;

        CSprings _springs;
        CSprite _straight_ruler = null;
        CSprite _line_ruler = null;
        CSprite _ruler_point = null;

        List<CWeightObject> _weightObjects = new List<CWeightObject>();

        Vector2 _last_drag_point = Vector2.Zero;
        Vector2 _current_drag_point = Vector2.Zero;
        int _touchID;

        bool _isLoaded = false;

        public SpringsPendulumPage()
        {
            InitializeComponent();

            // Get the content manager from the application
            contentManager = (Application.Current as App).Content;

            // Create a timer for this page
            timer = new GameTimer();
            timer.UpdateInterval = TimeSpan.FromTicks(333333);
            timer.Update += OnUpdate;
            timer.Draw += OnDraw;

            LayoutUpdated += TurnablePage_LayoutUpdated;
        }

        void TurnablePage_LayoutUpdated(object sender, EventArgs e)
        {
            if (ActualWidth == 0 || ActualHeight == 0)
                return;

            // see if we already have the right sized renderer
            if (elementRenderer != null &&
                elementRenderer.Texture != null &&
                elementRenderer.Texture.Width == (int)ActualWidth &&
                elementRenderer.Texture.Height == (int)ActualHeight)
            {
                return;
            }

            // dispose the current renderer
            if (elementRenderer != null)
                elementRenderer.Dispose();

            // create the renderer
            elementRenderer = new UIElementRenderer(LayoutRoot, (int)ActualWidth, (int)ActualHeight);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // Set the sharing mode of the graphics device to turn on XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

            // TODO: use this.content to load your game content here

            //_springs.WeightSprite = new CSprite(contentManager.Load<Texture2D>("Images/Springs/weight"));
            if (!_isLoaded)
            {
                _isLoaded = true;
                _springs = new CSprings(spriteBatch);
                _springs.Init(contentManager);
                _springs.Create(new Vector2(240, 0), 200.0f, 19);


                for (int i = 0; i < 5; i++)
                {
                    CWeightObject wo = new CWeightObject(spriteBatch, 50 * (i + 1) / 1000.0f, new CSprite(contentManager.Load<Texture2D>("Images/Springs/weight_" + i.ToString())));
                    wo.Init(contentManager);
                    wo.IdlePosition = new Vector2(48 + 96 * i, 700);
                    wo.SetWeightBoundSprite(new CSprite(contentManager.Load<Texture2D>("Images/Springs/weight_rect_" + i.ToString())));
                    _weightObjects.Add(wo);
                }
            }
            else
            {
                _springs.SpriteBatch = spriteBatch;
                _springs.Reset();
                foreach (CWeightObject wo in _weightObjects)
                {
                    wo.SpriteBatch = spriteBatch;
                }
            }

            _straight_ruler = new CSprite(contentManager.Load<Texture2D>("Images/Springs/straight_ruler"));
            _line_ruler = new CSprite(contentManager.Load<Texture2D>("Images/Springs/line_ruler"));
            _line_ruler.Position = new Vector2(30, _springs.getSpringsHeadHeight() + 290);
            _ruler_point = new CSprite(contentManager.Load<Texture2D>("Images/Springs/ruler_point"));
            _ruler_point.Position = new Vector2(30, _springs.getWeightPosition().Y);

            if (Settings.spring_save_active)
            {
                GetButton(ButtonTypes.Save).IsEnabled = true;
            }
            else
            {
                GetButton(ButtonTypes.Save).IsEnabled = false;
            }


            // Start the timer
            timer.Start();

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // Stop the timer
            timer.Stop();

            // Set the sharing mode of the graphics device to turn off XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

            base.OnNavigatedFrom(e);
        }

        /// <summary>
        /// Allows the page to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            // TODO: Add your update logic here  
            _l0.Text = (_springs.L0 / 3).ToString() + "(cm)";
            _lcb.Text = (_springs.LCB / 3).ToString() + "(cm)";
            _lmax.Text = (_springs.Lmax / 3).ToString() + "(cm)";
            _lmin.Text = (_springs.Lmin / 3).ToString() + "(cm)";
            _A.Text = _springs.A.ToString() + "(cm)";
            _d_l0.Text = ((_springs.LCB - _springs.L0) / 3).ToString() + "(cm)";

            _T.Text = ((float)(2 * Math.PI * (Math.Sqrt((_springs.LCB - _springs.L0) / 9.8f)))).ToString();
            _W.Text = _springs.W.ToString() + "(J)";
            _Wt.Text = _springs.Wt.ToString() + "(J)";
            _Wd.Text = _springs.Wd.ToString() + "(J)";

            _springs.Update(e);
            _ruler_point.setPositionY(_springs.getWeightPosition().Y);
            foreach (CWeightObject wo in _weightObjects)
            {
                wo.Update(e);
            }

            TouchCollection touches = TouchPanel.GetState();
            foreach (TouchLocation tl in touches)
            {
                switch (tl.State)
                {
                    case TouchLocationState.Pressed:
                        if (_springs.CurrentState == SpringState.WAIT)
                        {
                            if (_springs.WeightObject.Touch(tl))
                            {
                                _springs.CurrentState = SpringState.DRAG;
                                _last_drag_point = _current_drag_point = tl.Position;
                                _touchID = tl.Id;
                            }
                        }
                        foreach (CWeightObject wo in _weightObjects)
                        {
                            if (wo.IdleTouch(tl))
                            {
                                if (wo.CurrentState == WeightObjectState.IDLE)
                                {
                                    if (_springs.CurrentState == SpringState.IDLE)
                                    {
                                        _springs.AddWeightObject(wo);
                                        break;
                                    }
                                }
                                else
                                {
                                    _springs.Reset();
                                    _springs.WeightObject.Reset();
                                }
                            }
                        }

                        break;
                    case TouchLocationState.Moved:
                        if (_springs.CurrentState == SpringState.DRAG && _touchID == tl.Id)
                        {
                            _last_drag_point = _current_drag_point;
                            _current_drag_point = tl.Position;
                            float dy = _current_drag_point.Y - _last_drag_point.Y;
                            _springs.UpdateSpringLenght(dy);
                        }
                        break;
                    case TouchLocationState.Released:

                        if (tl.Id == _touchID)
                        {
                            _springs.SetInUseState();
                        }

                        break;
                }
            }
        }

        /// <summary>
        /// Allows the page to draw itself.
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.LightYellow);
            elementRenderer.Render();
            spriteBatch.Begin();
            spriteBatch.Draw(_straight_ruler.Texture, new Vector2(35.0f, _springs.getSpringsHeadHeight()), Color.White);
            spriteBatch.Draw(_line_ruler.Texture, _line_ruler.Position, null, Color.White, 0, _line_ruler.Origin, 1, SpriteEffects.None, 0);
            spriteBatch.Draw(_ruler_point.Texture, _ruler_point.Position, null, Color.White, 0, _ruler_point.Origin, 1, SpriteEffects.None, 0);
            spriteBatch.Draw(elementRenderer.Texture, Vector2.Zero, Microsoft.Xna.Framework.Color.White);
            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            _springs.Draw(e);
            foreach (CWeightObject wo in _weightObjects)
            {
                wo.Draw(e);
            }
            spriteBatch.End();
            // TODO: Add your drawing code here           

        }

        private void ApplicationBarInputData_Click(object sender, EventArgs e)
        {
            Settings.RenewSpringsDatas();
            NavigationService.Navigate(new Uri("/SpringsPendulum/SpringsPendulumDataPage.xaml", UriKind.Relative));
        }

        private void ApplicationBarInfo_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/SpringsPendulum/SpringPendulumInfoPage.xaml", UriKind.Relative));
        }

        private void ApplicationBarMenuItem_Click(object sender, System.EventArgs e)
        {
            NavigationService.Navigate(new Uri("/SpringsPendulum/SaveSpringPage.xaml", UriKind.Relative));
        }

        public enum ButtonTypes
        {
            Save = 0
        }
        public ApplicationBarIconButton GetButton(ButtonTypes whichButton)
        {
            return ApplicationBar.Buttons[(int)whichButton]
               as ApplicationBarIconButton;
        }

        private void ApplicationBarIconButton_Click(object sender, System.EventArgs e)
        {
            if (!Guide.IsVisible)
            {
                // display the guide

                Guide.BeginShowKeyboardInput(PlayerIndex.One,
                    "Tên",       // title for the page
                    "Nhập tên mô phỏng",  // question for user
                    null,             // default text
                    new AsyncCallback(GotTextName),  // callback method 
                    this);                       // object reference
            }


        }
        void GotTextName(IAsyncResult result)
        {
            if (result.IsCompleted)
            {
                List<SpringData> datas = SpringData.Load();

                string text = Guide.EndShowKeyboardInput(result);

                if (text != null)
                {
                    if (text == "")
                    {
                        text = "unknown";
                    }
                    Settings.spring_save_active = false;
                    SpringData data = new SpringData(text, Settings.SpringsK, Settings.SpringsEnviromentRatio);
                    datas.Add(data);
                    SpringData.SaveData(datas);
                }
            }
        }
    }
}